import React, { useMemo, useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Button } from 'antd';
import { createDesigner, TreeNode, createBehavior, createResource, GlobalRegistry } from '@inbiz/core';
import { SettingsForm } from '@inbiz/react-settings-form';
import {
  Designer,
  ResourceWidget,
  StudioPanel,
  SettingsPanel,
  TextWidget,
  useDesigner,
  useOperation,
  useWorkbench,
} from '@inbiz/react';
import { uid } from '@inbiz/shared';
import { transformToTreeNode } from '@inbiz/transformer';
import { InbizIcon } from '@inbiz/utils';
import * as Setters from '@inbiz/setters';
import { BasicWorkplace, getAllTree } from '@inbiz/render';
import { useComponets } from './useComponets';
import { localRegistry } from './common'
import icon from '../icons';
import { Field } from './materials/common/Field';
import { Form } from './materials/Form/designer';
import EdrmsLayout from '../../core/components/form/layout/SyncComponents/EdrmsLayout/designer/web'

import defaultFrom from './default.json';
import './index.less';

type IProps = {
  schema?: object;
  inbiz: any;
  style?: React.CSSProperties;
  onPreview?: (data: object) => void;
  onSave?: (data: object) => void;
  components: {
    name: string;
    controlId: string;
    title: string;
    extends: string;
    'x-component'?: string;
    'x-component-props'?: object;
    'x-decorator-props'?: object;
    propsSchema: {};
    designerProps: object;
    designerLocales?: object;
    props?: object;
  }[];
};

const MicoDesignWidget: React.FC<IProps> = forwardRef((props, ref) => {
  const [resource, $resource] = useState<any>([]);
  const [comp, $comp] = useState<any>(null);
  const [allComponents, $allComponents] = useComponets();

  const [list, listData, icons] = useMemo(() => {

    return generateComponents(props.components, comp);
  }, [props.components, comp]);

  useEffect(() => {
    const data: Object = allComponents.data || {};
    if (Object.keys(data).length > 0) {
      $comp({
        ...data
      });
    }
  }, [allComponents.data]);

  useEffect(() => {
    $resource(list);
  }, [list]);


  useEffect(() => {
    localRegistry()
    GlobalRegistry.getAllLocale()
  }, [])

  const engine = useMemo(() =>
    createDesigner({
      shortcuts: [],
      rootComponentName: 'Form',
    }), []);

  if (Object.keys(listData).length < 1) {
    return null
  }
  return (
    <Designer engine={engine}>
      <div className={'micoDesign-content'} style={props.style}>
        <StudioPanel>
          <div style={{ width: 300 }}>
            <ResourceWidget title="sources.Inputs" sources={[...resource]} />
          </div>

          <div className={'micoDesign-editor'}>
            <BasicWorkplace
              id="content"
              flexable={true}
              components={{
                ...comp,
                ...listData,
                Field,
                Form,
                EdrmsLayout
              }}
            >
              <OthterElement
                schema={props.schema}
                onSave={props.onSave}
                onPreview={props.onPreview}
                resource={resource}
                setResource={$resource}
                __ref={ref}
                list={list}
              />
            </BasicWorkplace>
          </div>

          <SettingsPanel title="sources.PropertySettings">
            <SettingsForm
              componentIcon={icons}
              // @ts-ignore
              components={Setters}
              nameKey={'controlId'}
              appInfo={props.inbiz.appInfo}
            />
          </SettingsPanel>
        </StudioPanel>
      </div>
    </Designer>
  );
});

// 组件与树取补集
const resourceFilter = (sources: any[], targetTree: TreeNode) => {
  if (!targetTree) {
    return sources;
  }
  const data = sources.filter((item) => {
    if (targetTree.children.length > 0) {
      const isShow = targetTree.children.some((item2) => {
        return item2.props && item2.props['x-component'] == item.Behavior[0]['name'];
      });
      return !isShow;
    }
    return true;
  });
  return data;
};

interface TOthterElement {
  schema?: object;
  onPreview?: (data: object) => void;
  onSave?: (data: object) => void;
  resource: [];
  setResource: Function;
  __ref: any;
  list: any;
}
const OthterElement = (props: TOthterElement) => {
  const [refresh, $refresh] = useState('');
  const designer = useDesigner();
  const workbench = useWorkbench();

  // 容器定位
  const currentWorkspace = workbench?.activeWorkspace || workbench?.currentWorkspace;
  const currentWorkspaceId = currentWorkspace?.id;
  const operation = useOperation(currentWorkspaceId);
  const content = operation.tree.children[0];

  // 数据初始化
  useEffect(() => {
    designer.workbench.eachWorkspace((workspace) => {
      if (props.schema) {
        workspace.operation.tree.from(transformToTreeNode(props.schema) as Object);
        $refresh(uid(6));
      } else {
        workspace.operation.tree.from(transformToTreeNode(defaultFrom.content) as Object);
      }
    });
  }, [props.schema]);

  // 动作监听
  useEffect(() => {
    designer.subscribeWith(
      ['append:node', 'insert:after', 'insert:before', 'insert:children', 'remove:node'],
      (event) => {
        $refresh(uid(6));
      },
    );
  }, []);

  // 资源筛选
  useEffect(() => {
    const filResource = resourceFilter(props.list, content);
    props.setResource(filResource);
  }, [props.list, content, refresh]);

  // 获取
  const getSchema = () => {
    let schema: any = getAllTree(designer.workbench);
    console.log({ schema })
    return schema;
  };

  const preview = () => {
    const schema = getSchema();
    props.onPreview && props.onPreview(schema);
  };

  const save = () => {
    const schema = getSchema();
    props.onSave && props.onSave(schema);
  };

  useImperativeHandle(
    props.__ref,
    () => ({
      getSchema: () => {
        return getSchema();
      },
      refreshSchema: () => {
        $refresh(uid(6));
      },
      clearSchema: () => {
        designer.workbench.eachWorkspace((workspace) => {
          workspace.operation.tree.from(transformToTreeNode(defaultFrom.content) as Object);
        });
        $refresh(uid(6));
      },
    }),
    [props.schema, designer],
  );

  return (
    <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'right' }}>
      <div>
        <Button type="link" onClick={preview} className="edrmsButton">
          <InbizIcon type="icon-inbiz_other-eye" style={{ marginRight: 5 }} />
          <TextWidget>global.preview</TextWidget>
        </Button>
        {props.onSave && (
          <Button type="link" onClick={save} className="edrmsButton edrmsButton-save">
            <InbizIcon type="icon-inbiz_basic-save" style={{ marginRight: 5 }} />
            <TextWidget>global.save</TextWidget>
          </Button>
        )}
      </div>
    </div>
  );
};

function generateComponents(components: IProps['components'], allComponents: any) {
  if (components?.length && allComponents) {
    const data = {},
      icons = {};
    const list = components.map((item) => {
      const component = { ...allComponents[item.extends] };
      component.Behavior = createBehavior({
        name: item.name,
        extends: ['Field'],
        // @ts-ignore
        selector: (node: { props: { [x: string]: string } }) =>
          node.props?.['x-component'] === item.name,
        designerProps: {
          propsSchema: item.propsSchema,
          ...(item.designerProps || {}),
        }, //@ts-ignore
        designerLocales: item.designerLocales,
      });

      const { icon: iconStr, elements } = component.Resource[0];
      const { props } = elements[0];
      component.Resource = createResource({
        icon: iconStr,
        title: item.title,
        elements: [
          {
            componentName: 'Field',
            props: {
              controlId: item.controlId,
              ...props,
              title: { ...props.title, value: item.title },
              'x-component': item.name,
              'x-component-props': Object.assign(
                {},
                props['x-component-props'],
                item['x-component-props'] || {},
              ),
              'x-decorator-props': Object.assign({}, item['x-decorator-props'] || {}),
              ...(item.props || {}),
            },
          },
        ],
      });
      icons[item.name] = icon[iconStr] || iconStr;
      data[item.name] = component;
      return component;
    });
    return [list, data, icons] as const;
  } else {
    return [[], {}, {}] as const;
  }
}

export default MicoDesignWidget
